﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace Shapes
{
    class Ellipse: Figure
    {
        int axisA, axisB;
        Rectangle rect;
        public Ellipse(int A, int B, int x, int y)
            : base(x, y)
        {
            axisA = A; axisB = B;
            rect = Init();
        }
        public override void Show(Graphics g, Pen pen, Brush brush)
        {
            rect = Init();
            g.DrawEllipse(pen, rect);
            g.FillEllipse(brush, rect);
        }
        public override Rectangle Region_Capture()
        {
            rect = Init();
            return rect;
        }
        Rectangle Init()
        {
            int a = Convert.ToInt32(axisA * scale);
            int b = Convert.ToInt32(axisB * scale);
            int leftupX = center.X - a;
            int leftupY = center.Y - b;
            return (new Rectangle(leftupX, leftupY, 2 * a, 2 * b));
        }
    }
    /// <summary>
    /// Класс Circle - потомок класса Ellipse.
    /// </summary>
    public class Circle : Ellipse
    {
        public Circle(int radius, int x,
            int y)
            : base(radius, radius, x, y)
        {
            //Круг - это эллипс с равными полуосями (радиусом круга)
        }
    }
    /// <summary>
    /// Класс LittleCircle - потомок класса Circle.
    /// </summary>
    public class LittleCircle : Circle
    {
        public LittleCircle(int x, int y)
            : base(4, x, y)
        {
            // маленький круг радиуса 4
        }
    }
    /// <summary>
    /// Класс Rect - потомок класса Figure.
    /// </summary>
    public class Rect : Figure
    {
        int sideA, sideB;
        Rectangle rect;
        public Rect(int sideA, int sideB, int x, int y)
            : base(x, y)
        {
            this.sideA = sideA; this.sideB = sideB;
            rect = Init();
        }
        public override void Show(Graphics g, Pen pen, Brush brush)
        {
            rect = Init();
            g.DrawRectangle(pen, rect);
            g.FillRectangle(brush, rect);
        }
        public override Rectangle Region_Capture()
        {
            rect = Init();
            return rect;
        }
        Rectangle Init()
        {
            int a = Convert.ToInt32(sideA * scale);
            int b = Convert.ToInt32(sideB * scale);
            int leftupX = center.X - a / 2;
            int leftupY = center.Y - b / 2;
            return (new Rectangle(leftupX, leftupY, a, b));
        }
    }
    /// <summary>
    /// Класс Square - потомок класса Rect.
    /// </summary>
    public class Square : Rect
    {
        public Square(int side, int x, int y)
            : base(side, side, x, y)
        {
            //квадрат - это прямоугольник с равными сторонами
        }
    }
    /// <summary>
    /// Класс Person - потомок класса Figure, 
    /// клиент классов Circle, Rect, LittleCircle.
    /// </summary>
    public class Person : Figure
    {
        int head_h;
        Circle head;
        Rect body;
        LittleCircle nose;
        public Person(int head_h, int x, int y) : base(x, y)
        {
            //head_h - радиус головы, x,y - ее центр.
            //остальные размеры исчисляются относительно 
            //размера головы.
            this.head_h = head_h;
            head = new Circle(head_h, x, y);
            int body_x = x;
            int body_y = y + 3 * head_h;
            int body_w = 2 * head_h;
            int body_h = 4 * head_h;
            body = new Rect(body_w, body_h, body_x, body_y);
            nose = new LittleCircle(x + head_h + 2, y);
        }
        public override void Show(System.Drawing.Graphics g, System.Drawing.Pen pen, System.Drawing.Brush brush)
        {
            int h = Convert.ToInt32(head_h * scale);
            //head
            int top_x = center.X - h;
            int top_y = center.Y - h;
            g.DrawEllipse(pen, top_x, top_y, 2 * h, 2 * h);
            g.FillEllipse(brush, top_x, top_y, 2 * h, 2 * h);
            //body
            top_y += 2 * h;
            g.DrawRectangle(pen, top_x, top_y, 2 * h, 4 * h);
            g.FillRectangle(brush, top_x, top_y, 2 * h, 4 * h);
            //nose
            top_y -= h;
            top_x += 2 * h;
            g.DrawEllipse(pen, top_x, top_y, 8, 8);
            g.FillEllipse(brush, top_x, top_y, 8, 8);
        }
        public override System.Drawing.Rectangle Region_Capture()
        {
            int h = Convert.ToInt32(head_h * scale);
            int top_x = center.X - h;
            int top_y = center.Y - h;
            return new
                System.Drawing.Rectangle(top_x, top_y, 2 * h, 2 * h);
        }
    }
    /// <summary>
    /// Класс TwoWayList(G)  описывает двусвязный список с 
    /// курсором. Элементами списка являются объекты 
    /// TwoLinkable, хранящие, помимо указателей на двух 
    /// преемников, объекты типа G.Курсор будет определять 	
    /// текущий (активный) элемент списка. Класс будет
    /// определять симметричные операции по отношению к 
    /// курсору.
    /// Конструкторы: 
    /// Конструктор без параметров будет создавать пустой 
    /// список
    /// Запросы:
    /// empty: require: true; возвращает true для пустого списка
    /// item: require: not empty(); возвращает активный элемент типа G; 
    /// require: true; возвращает число элементов списка; 
    /// count: count in[0,n] (count == 0) eqviv empty(); 
    /// index: require: not empty(); возвращает индекс активного элемента.
    /// search_res: require: true; возвращает true, если последний поиск был успешным.
    /// Команды:
    /// put_left(elem): require: true; 
    /// ensure: добавить новый элемент (elem) слева от курсора;
    /// put_right(elem): require: true; 
    /// ensure: добавить новый элемент (elem) справа от курсора;
    /// remove: require: not empty(); 
    /// ensure: удалить активный элемент;
    /// особо обрабатывается удаление последнего и единственного элементов
    /// операции с курсором:
    /// start: require: true; 
    /// ensure: сделать активным первый элемент;
    /// finish: require: true; 
    /// ensure: сделать активным последний элемент; 
    /// go_prev: require: not (index = 1); 
    /// ensure: сделать активным предыдущий элемент;
    /// go_next: require: not (index = count); 
    /// ensure: сделать активным последующий элемент;
    /// go_i(i): require:  (i in [1, count]); 
    /// ensure: сделать активным элемент с индексом i;
    /// операции поиска:
    /// search_prev(elem): require: not (index = 1); 
    /// ensure: сделать активным первый элемент elem слева от курсора;
    /// Успех или неуспех поиска сохранять в булевской 
    /// переменной search_res
    /// search_next: require: not (index = count); 
    /// ensure: сделать активным первый элемент elem справа от курсора;
    /// успех или неуспех поиска сохранять в булевской переменной search_res
    /// </summary>
    public class TwoWayList
    {
        public TwoWayList()
        {
            first = cursor = last = null;
            count = index = 0;
            search_res = false;
        }//конструктор
        /// <summary>
        /// first, cursor, last - ссылки на первый,
        /// активный и последний элементы списка
        /// Запросы count, index search_res также 
        /// реализуются атрибутами.
        /// Запросы empty, item реализуются функциями 
        /// </summary>
        protected TwoLinkable first, cursor, last;
        protected int count, index;
        protected bool search_res;
        //доступ на чтение к закрытым свойствам;
        public int Count
        {
            get
            {
                return (count);
            }
        }
        public int Index
        {
            get
            {
                return (index);
            }
        }
        public bool Search_res
        {
            get
            {
                return (search_res);
            }
        }
        /// <summary>
        /// require: true; возвращает true для непустого списка
        /// </summary>
        /// <returns></returns>
        public bool empty()
        {
            return (first == null);
        }//empty
        /// <summary>
        /// require: not empty(); возвращает активный 
        /// элемент типа G;
        /// </summary>
        /// <returns></returns>
        public Figure item()
        {
            return (cursor.Item);
        }//item
        /// <summary>
        /// require: true; 
        /// ensure: добавить новый элемент (elem) слева 
        /// от курсора;
        /// </summary>
        /// <param name="elem">Тип Figure играет роль 
        /// родового типа G
        /// хранимого элемента elem</param>
        public void put_left(Figure elem)
        {
            TwoLinkable newitem = new TwoLinkable();
            newitem.Item = elem;
            newitem.Next = cursor;
            if (empty())	//список пуст
            {
                first = cursor = last = newitem;
                index = 1; count = 1;
            }
            else
            {
                if (index == 1)
                    first = newitem;
                else
                    cursor.Prev.Next = newitem;
                newitem.Prev = cursor.Prev; cursor.Prev = newitem;
                count++; index++;
            }
        }//put_right
        /// <summary>
        /// require: true; 
        /// ensure: добавить новый элемент (elem) справа 
        /// от курсора;
        /// </summary>
        /// <param name="elem">Тип Figure играет роль 
        /// родового типа G
        /// хранимого элемента elem</param>
        public void put_right(Figure elem)
        {
            TwoLinkable newitem = new TwoLinkable();
            newitem.Item = elem;
            newitem.Prev = cursor;
            if (empty())	//список пуст
            {
                first = cursor = last = newitem;
                index = 1; count = 1;
            }
            else
            {
                if (index == count)
                    last = newitem;
                else
                    cursor.Next.Prev = newitem;

                newitem.Next = cursor.Next; cursor.Next = newitem;
                count++;
            }
        }//put_right
        public void remove()
        {
            if (count == 1)
            {
                first = last = cursor = null;
                index = 0;
            }
            else if (index == 1)
            {
                first = cursor.Next;
                cursor.Prev = null;
                cursor = cursor.Next;
            }
            else if (index == count)
            {
                last = cursor.Prev;
                cursor.Next = null;
                cursor = cursor.Prev;
                index--;
            }
            else
            {
                cursor.Prev.Next = cursor.Next;
                cursor.Next.Prev = cursor.Prev;
                cursor = cursor.Next;
            }
            count--;
        }//remove
        /// операции с курсором:
        /// <summary>
        /// start: require: true; 
        /// ensure: сделать активным первый элемент;
        /// </summary>
        public void start()
        {
            cursor = first; index = 1;
        }//start
        /// <summary>
        /// finish: require: true; 
        /// ensure: сделать активным последний элемент; 
        /// </summary>
        public void finish()
        {
            cursor = last; index = count;
        }//finish
        /// <summary>
        /// go_prev: require: not (index = 1); 
        /// ensure: сделать активным предыдущий элемент;
        /// </summary>
        public void go_prev()
        {
            cursor = cursor.Prev; index--;
        }// go_prev
        /// <summary>
        /// go_next: require: not (index = count); 
        /// ensure: сделать активным последующий элемент;
        /// </summary>
        public void go_next()
        {
            cursor = cursor.Next; index++;
        }// go_next
        /// <summary>
        /// go_i(i): require:  (i in [1, count]); 
        /// ensure: сделать активным элемент с индексом i;
        /// </summary>
        /// <param name="i"></param>
        public void go_i(int i)
        {
            if (i > index)
                while (i > index)
                {
                    cursor = cursor.Next; index++;
                }
            else if (i < index)
                while (i < index)
                {
                    cursor = cursor.Prev; index--;
                }
        }// go_i
        /// операции поиска:
        /// <summary>
        /// search_prev(elem): require: not (index = 1); 
        /// ensure: сделать активным первый элемент elem 
        /// слева от курсора;
        /// </summary>
        /// <param name="elem">искомый элемент</param>
        public virtual void search_prev(Figure elem)
        {
            bool found = false;
            while (!found && (index != 1))
            {
                cursor = cursor.Prev; index--;
                found = (elem == item());
            }
            search_res = found;
        }// search_prev
        /// <summary>
        /// успех или неуспех поиска сохранять в булевской 
        /// переменной search_res
        /// search_next: require: not (index = count); 
        /// ensure: сделать активным первый элемент elem 
        /// справа от курсора;
        /// успех или неуспех поиска сохранять в булевской 
        /// переменной search_res
        /// </summary>
        /// <param name="elem"></param>
        public virtual void search_next(Figure elem)
        {
            bool found = false;
            while (!found && (index != count))
            {
                cursor = cursor.Next; index++;
                found = (elem == item());
            }
            search_res = found;
        }//search_next	
    }
    /// <summary>
    /// Класс Linkable(T)задает элементы списка,включающие:
    /// информационное поле типа T - item 
    /// ссылку на элемент типа Linkable - next
    /// Функции:
    /// конструктор new: -> Linkable
    /// запросы: 
    /// Get_Item: Linkable -> T
    /// Get_Next: Linkable -> Linkable 
    /// процедуры:
    /// Set_Item: Linkable*T -> Linkable
    /// Set_Next: Linkable*Linkable -> Linkable 
    /// Роль типа T играет Figure
    /// </summary>
    public class Linkable
    {
        public Linkable()
        {
            item = null; next = null;
        }
        /// <summary>
        /// закрытые атрибуты класса
        /// </summary>
        Figure item;
        Linkable next;
        /// <summary>
        /// процедуры свойства для доступа к полям класса
        /// </summary>
        public Figure Item
        {
            get
            {
                return (item);
            }
            set
            {
                item = value;
            }
        }
        public Linkable Next
        {
            get
            {
                return (next);
            }
            set
            {
                next = value;
            }
        }
    }//class Linkable
    /// <summary>
    /// Класс TwoLinkable задает элементы с двумя ссылками 
    /// </summary>
    public class TwoLinkable
    {

        public TwoLinkable()
        {
            prev = next = null;
        }
        /// <summary>
        /// закрытые атрибуты класса
        /// </summary>
        TwoLinkable prev, next;
        Figure item;
        /// <summary>
        /// процедуры свойства для доступа к полям класса
        /// </summary>
        public Figure Item
        {
            get
            {
                return (item);
            }
            set
            {
                item = value;
            }
        }
        public TwoLinkable Next
        {
            get
            {
                return (next);
            }
            set
            {
                next = value;
            }
        }
        public TwoLinkable Prev
        {
            get
            {
                return (prev);
            }
            set
            {
                prev = value;
            }
        }
    }//class TwoLinkable
}
